import { Controller } from 'egg';
import * as sharp from 'sharp';
import { parse, join, extname } from 'path';
import { nanoid } from 'nanoid';
import { createWriteStream } from 'fs';
import { pipeline } from 'stream/promises';

export default class UtilsController extends Controller {
  async fileLocalUpload() {
    const { ctx } = this;
    const { filepath } = ctx.request.files[0];
    const imageSource = sharp(filepath);
    let thumbnailUrl = '';
    const metaData = await imageSource.metadata();
    if (metaData.width && metaData.width > 300) {
      const { name, ext, dir } = parse(filepath);
      const thumbnailFilePath = join(dir, `${name}-thumbnailFilePath${ext}`);
      await imageSource.resize({ width: 300 }).toFile(thumbnailFilePath);
      thumbnailUrl = this.pathToURL(thumbnailFilePath);
    }
    const url = this.pathToURL(filepath);
    ctx.helper.success({
      ctx,
      res: { url, thumbnailUrl: thumbnailUrl ? thumbnailUrl : url },
    });
  }

  async fileUploadByStream() {
    const { ctx, app } = this;
    const stream = await this.ctx.getFileStream();
    const uid = nanoid(6);
    const saveFilePath = join(
      app.config.baseDir,
      'uploads',
      uid + extname(stream.filename),
    );
    const saveThumbnailPath = join(
      app.config.baseDir,
      'uploads',
      uid + '_thumbnail' + extname(stream.filename),
    );
    const target = createWriteStream(saveFilePath);
    const target2 = createWriteStream(saveThumbnailPath);
    const savePromise = pipeline(stream, target);
    const transformer = sharp().resize({ width: 300 });
    const thumbnailPromise = pipeline(stream, transformer, target2);
    try {
      await Promise.all([savePromise, thumbnailPromise]);
    } catch (e) {
      return ctx.helper.error({ ctx, errorType: 'imageUploadFail' });
    }
    ctx.helper.success({
      ctx,
      res: {
        url: this.pathToURL(saveFilePath),
        thumbnailUrl: this.pathToURL(saveThumbnailPath),
      },
    });
  }

  private pathToURL(filePath: string) {
    const { app } = this;
    return filePath
      .replace(app.config.baseDir, app.config.baseUrl)
      .replace(/\\/g, '/');
  }
}
